using System;
using System.Activities;
using Microsoft.Xrm.Sdk.Workflow;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;

namespace CRM2011WorkflowUtilities
{
    public class QualifyLead : CodeActivity
    {
        protected override void Execute(CodeActivityContext executionContext)
        {
            //Create the context and tracing service
            IExecutionContext context = executionContext.GetExtension<IExecutionContext>();
            IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
            ITracingService tracer = executionContext.GetExtension<ITracingService>();

            try  
            {
                EntityReference lead = Lead.Get(executionContext);

                bool createOpportunity = CreateOpportunity.Get(executionContext);
                bool createContact = CreateContact.Get(executionContext);
                bool createAccount = CreateAccount.Get(executionContext);
                EntityReference parentContact = ParentContact.Get(executionContext);;
                EntityReference parentAccount = ParentAccount.Get(executionContext);;
                EntityReference currency = Currency.Get(executionContext);

                // Validate opportunity transaction currency is provided
                if (createOpportunity)
                {
                    if (currency == null)
                    {
                        Helpers.Throw("If qualifying to opportunity then the transaction currency is required");
                    }
                    if (parentContact == null && parentAccount == null)
                    {
                        Helpers.Throw("If qualifying to opportunity then the parent account or the parent contact is required in the workflow step configuration");
                    }
                }

                // Validate qualifying to at least one record
                if (!createOpportunity && !createContact && !createContact)
                {
                    Helpers.Throw("To qualify a lead you must select either a contact, account or opportunity to be created in the workflow step configuration.");
                }

                QualifyLeadRequest req = new QualifyLeadRequest()
                {
                    CreateAccount = createAccount,
                    CreateContact = createContact,
                    CreateOpportunity = createOpportunity,
                    LeadId = lead,
                    Status = NewLeadStatus.Get(executionContext),
                    OpportunityCurrencyId = currency,
                    OpportunityCustomerId = parentContact == null ? parentAccount : parentContact,
                };
                QualifyLeadResponse resp = (QualifyLeadResponse) service.Execute(req);
                foreach (EntityReference e in resp.CreatedEntities)
                {
                    if (e.LogicalName.Equals("contact", StringComparison.InvariantCultureIgnoreCase))
                    {
                        QualifiedContact.Set(executionContext, e);
                    }
                    else if (e.LogicalName.Equals("account", StringComparison.InvariantCultureIgnoreCase))
                    {
                        QualifiedAccount.Set(executionContext, e);
                    }
                    else if (e.LogicalName.Equals("opportunity", StringComparison.InvariantCultureIgnoreCase))
                    {
                        QualifiedOpportunity.Set(executionContext, e);
                    }
                }
                if (!createContact)
                {
                    QualifiedContact.Set(executionContext, null);
                }
                if (!createAccount)
                {
                    QualifiedAccount.Set(executionContext, null);
                }
                if (!createOpportunity) 
                {
                    QualifiedOpportunity.Set(executionContext, null);
                }
            }
            catch (Exception ex)
            {
                tracer.Trace(String.Format("Exception occurred: {0} {1}", ex.Message, ex.StackTrace));

               Helpers.Throw(String.Format("An error occurred in the {0} plug-in.",
                       this.GetType().ToString()),
                     ex);
            }

            return;
        }

        #region Input Parameters

        [RequiredArgument]
        [ReferenceTarget("lead")]
        [Input("Lead")]
        public InArgument<EntityReference> Lead { get; set; }

        [Input("Status of the lead after qualifying")]
        [AttributeTarget("lead", "statuscode")]
        [Default("3")]
        [RequiredArgument]
        public InArgument<OptionSetValue> NewLeadStatus { get; set; }

        [Input("Create Contact")]
        [RequiredArgument]
        [Default("true")]
        public InArgument<bool> CreateContact { get; set; }

        [Input("Create Account")]
        [RequiredArgument]
        [Default("true")]
        public InArgument<bool> CreateAccount { get; set; }

        [Input("Create Opportunity")]
        [RequiredArgument]
        [Default("false")]
        public InArgument<bool> CreateOpportunity { get; set; }

        [ReferenceTarget("transactioncurrency")]
        [Input("Transaction Currency of the Opportunity.")]
        public InArgument<EntityReference> Currency { get; set; }

        [ReferenceTarget("contact")]
        [Input("Parent Contact of Opportunity")]
        public InArgument<EntityReference> ParentContact { get; set; }

        [ReferenceTarget("account")]
        [Input("Parent Account of Opportunity (applicable only if parent contact not provided)")]
        public InArgument<EntityReference> ParentAccount { get; set; }

        #endregion

        #region Output Parameters

        [Output("Qualified Contact")]
        [ReferenceTarget("contact")]
        public OutArgument<EntityReference> QualifiedContact { get; set; }

        [Output("Qualified Account")]
        [ReferenceTarget("account")]
        public OutArgument<EntityReference> QualifiedAccount { get; set; }

        [Output("Qualified Opportunity")]
        [ReferenceTarget("opportunity")]
        public OutArgument<EntityReference> QualifiedOpportunity { get; set; }

        #endregion
    }
}
